feat(js): send tab state with session token requests#9215
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 090f789 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
API Changes Report
Summary
🔴 Breaking changes index (1)Every breaking change, up front. Full diffs are in the package sections below.
@clerk/uiVersion: 1.25.7 → 1.25.6 Subpath
|
📝 WalkthroughWalkthroughSession token requests now include Estimated code review effort: 3 (Moderate) | ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/electron
@clerk/electron-passkeys
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-google-signin
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
524fe1a to
816773d
Compare
Since the proactive refresh landed, the tab that last minted re-arms its own refresh timer, so refresh duty sticks to one tab regardless of focus and a hidden tab can hold it indefinitely, under-reporting focused activity. Attach the refresh timer only in focused tabs and poll at 1.5s while focused (5s otherwise) so duty migrates to the tab the user is actually in.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/clerk-js/src/core/resources/Session.ts`:
- Around line 242-252: Re-check isTabFocused() !== false when each scheduled
refresh executes, not only when callbacks are created. Guard the hydrated-token
callback at packages/clerk-js/src/core/resources/Session.ts:242-252, the
network-minted token refresh at
packages/clerk-js/src/core/resources/Session.ts:593-598, and subsequent
refresh-cycle execution at
packages/clerk-js/src/core/resources/Session.ts:664-669, preferably at
`#refreshTokenInBackground` or each callback entry point; add a
focused-to-unfocused transition test and ensure refresh responsibility follows
the currently focused tab.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: da7805cb-17d8-4b2f-81d3-a100cc606762
📒 Files selected for processing (6)
.changeset/focused-refresh-bias.mdpackages/clerk-js/src/core/auth/SessionCookiePoller.tspackages/clerk-js/src/core/auth/__tests__/SessionCookiePoller.test.tspackages/clerk-js/src/core/resources/Session.tspackages/clerk-js/src/core/resources/__tests__/Session.test.tspackages/clerk-js/src/utils/isTabFocused.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
clerk/clerk_go(manual) → reviewed against open PR#20618nikos/tokens-tab-stateinstead of the default branchclerk/dashboard(manual)clerk/accounts(manual)clerk/backoffice(manual)clerk/clerk(manual)clerk/clerk-docs(manual)clerk/cloudflare-workers(manual)
Post-review cleanup, no behavior change: getTabState moves next to isTabFocused so the document guard exists once, the three conditional onRefresh spreads collapse into a focusedRefresh helper, and the three copies of the document descriptor stub/restore machinery in tests become one shared helper that also covers visibilityState.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/clerk-js/src/core/resources/Session.ts (1)
493-498: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftForward
tab_statethrough FAPI before releasing this client change.The linked
clerk/clerk_gobranch accepts the form parameter but drops it:CreateSessionTokenParamsand its downstream token-mint call have no tab-state field. This client will send the value, but the service cannot consume it. Add and forward the field server-side before rollout.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/clerk-js/src/core/resources/Session.ts` around lines 493 - 498, Update the server-side CreateSessionTokenParams flow to accept the tab_state form parameter and add a corresponding tab-state field to the downstream token-mint request. Forward the received value through the create-session-token handler into the token-mint call, preserving existing behavior when it is absent, before releasing the client change.Source: Linked repositories
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/clerk-js/src/core/resources/Session.ts`:
- Around line 493-498: Update the server-side CreateSessionTokenParams flow to
accept the tab_state form parameter and add a corresponding tab-state field to
the downstream token-mint request. Forward the received value through the
create-session-token handler into the token-mint call, preserving existing
behavior when it is absent, before releasing the client change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: c81db20c-b5aa-4330-821e-da32771a5bc2
📒 Files selected for processing (5)
packages/clerk-js/src/core/auth/__tests__/SessionCookiePoller.test.tspackages/clerk-js/src/core/resources/Session.tspackages/clerk-js/src/core/resources/__tests__/Session.test.tspackages/clerk-js/src/test/document-helpers.tspackages/clerk-js/src/utils/isTabFocused.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
clerk/clerk_go(manual) → reviewed against open PR#20618nikos/tokens-tab-stateinstead of the default branchclerk/dashboard(manual)clerk/accounts(manual)clerk/backoffice(manual)clerk/clerk(manual)clerk/clerk-docs(manual)clerk/cloudflare-workers(manual)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/clerk-js/src/core/auth/tests/SessionCookiePoller.test.ts
- packages/clerk-js/src/core/resources/tests/Session.test.ts
Why
Session activity counts pretty much every /tokens call as user activity, but backgrounded tabs keep refreshing tokens on a timer, so idle sessions look active. There's nothing on the wire to tell a foreground mint from a background one. On top of that, since the proactive refresh landed in #7317 the tab that last minted re-arms its own refresh timer, so refresh duty sticks to one tab regardless of focus. A hidden tab can hold it indefinitely while the user works elsewhere, which would skew the new signal in multi-tab apps.
What changed
Non-template session token requests now include a tab_state body param with one of focused, visible or hidden, derived at request time: document.hasFocus() wins, then visibilityState, and the param is omitted when document doesn't exist (service workers, headless runtimes). Template tokens and touch are untouched.
Refresh ownership is also biased toward the focused tab: network mints attach the proactive refresh callback only when the tab is focused, and the session poller ticks at 1.5s while focused (5s otherwise). An unfocused tab still mints when its turn comes, it just doesn't keep the job, so within a cycle or two the refreshes (and the tab_state they report) come from the tab the user is actually in. Browsers with no focused tab fall back to the regular 5s poller floor, and runtimes without a usable document behave exactly as before.
Blockers / related
Merging is safe but releasing isn't yet: FAPI rejects unknown form params with a 422, so this must not go out in a clerk-js release before clerk/clerk_go #20618 is deployed. The Session Minter passes the param through untouched, no changes needed there.